<?php
/**
 * Created by PhpStorm.
 * User: 王松
 * Time: 2017/9/12 11:13
 */

namespace App\Project\Reserve;

use App\Models\Reservation\PoolReject;
use App\Models\Reservation\Schedule;
use App\User;
use Carbon\Carbon;
use App\Models\Reservation\Reservation;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Reservation\Pool as PoolModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Project\Reserve\Exceptions\ReservationForbiddenException;

class Pool
{
    /**
     * 患者池列表
     * @param null $patientWhere
     * @param null $times
     * @param null $reception
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function listing($patientWhere = null, $times = null, $reception = null)
    {
        $query = PoolModel::select('st_pools.*')
                          ->where('st_reservations.hospital_id', \Auth::user()->hospital_id)
                          ->with([
                              'patient', 'reservation' => function (BelongsTo $query) {
                                  $query->onlyTrashed()->select('id', 'time', 'start', 'end');
                              }
                          ])
                          ->orderByDesc('st_pools.id');

        if ($patientWhere) {
            $query = $query->whereHas('patient', function (Builder $builder) use ($patientWhere) {
                $builder->where($patientWhere);
            });
        }

        if ($times) {
            $query->join('st_reservations', 'st_reservations.id', 'st_pools.reservation_id'
                )->where(function (Builder $query) use ($times) {
                if ((isset($times[0]) && !empty($times[0])) && (isset($times[1]) && !empty($times[1]))) {
                    $query->whereBetween('st_reservations.time', $times);
                } elseif (isset($times[0]) && !empty($times[0])) {
                    $query->where('st_reservations.time', '>=', $times[0]);
                } elseif (isset($times[1]) && !empty($times[1])) {
                    $query->where('st_reservations.time', '<=', $times[1]);
                }
            });
        }

        if (\Auth::user()->isA('nurse')) {
            return $query->paginate();
        }

        $receptionMethod = $this->getReceptionMethod($reception);

        return $query->whereNotReject(\Auth::user())->$receptionMethod(\Auth::user())->paginate();
    }

    /**
     * 创建一条患者池记录
     * @param \App\Models\Reservation\Reservation $reservation
     * @return \Illuminate\Database\Eloquent\Model|static
     */
    public function create(Reservation $reservation)
    {
        $data = [
            'patient_id'     => $reservation->patient_id,
            'reservation_id' => $reservation->id,
            'hospital_id'    => $reservation->hospital_id,
        ];

        return PoolModel::create($data);
    }

    /**
     * 根据预约的ID，创建患者池数据
     * @param $id
     * @return bool
     */
    public function createById($id)
    {
        $pool = null;
        $now  = Carbon::now()->toDateTimeString();

        if (is_array($id)) {
            $pool = Reservation::whereIn('id', $id)
                               ->select('id as reservation_id', 'patient_id', 'hospital_id')
                               ->onlyTrashed()
                               ->get()
                               ->map(function (Reservation $reservation) use ($now) {
                                   return $this->poolFromReservation($reservation, $now);
                               })->toArray();
        } else {
            $reservation = Reservation::where('id', $id)
                                      ->select('id as reservation_id', 'patient_id', 'hospital_id')
                                      ->onlyTrashed()->first();

            $pool = $this->poolFromReservation($reservation, $now);
        }

        return \DB::table('st_pools')->insert($pool);
    }

    /**
     * 将一条患者池记录的患者分配给一个医生(医院管理员权限)
     * @param $doctor
     * @param $pool_ids
     * @return bool|int
     * @throws \App\Project\Reserve\Exceptions\ReservationForbiddenException
     */
    public function assignTo($doctor, $pool_ids)
    {
        if (!$this->isHospitalAdmin()) {
            throw new ReservationForbiddenException('无分配患者池患者的的权限！');
        }

        return $this->accept($doctor, $pool_ids);
    }

    /**
     * @param $doctor
     * @param $pool_ids
     * @return bool|int
     */
    public function accept($doctor, $pool_ids)
    {
        $doctor_id = is_numeric($doctor) ? $doctor : $doctor->id;

        $reservation_ids = PoolModel::whereIn('id', $pool_ids)
                                    ->select(['id', 'reservation_id'])
                                    ->get();

        $reservations = Reservation::whereIn('id', $reservation_ids->pluck('reservation_id')->toArray())
                                   ->onlyTrashed()->get();

        $schedules = Schedule::whereIn('time', $reservations->pluck('time'))
                             ->where('doctor_id', $doctor_id)->get()->keyBy('time');

        $can = $reservations->filter(function (Reservation $reservation) use ($schedules) {

            return $schedules->has($reservation->time) && array_key_exists($reservation->am,
                    $schedules->get($reservation->time)['workload']);
        })->pluck('id')->toArray();

        if ($can) {
            $result = Reservation::whereIn('id', $can)->onlyTrashed()->update([
                'doctor_id'  => $doctor_id,
                'status'     => 1,
                'deleted_at' => null,
            ]);

            $deletes = array_intersect(
                $reservation_ids->pluck('id', 'reservation_id')->toArray(),
                $pool_ids
            );

            !$deletes ?: PoolModel::whereIn('id', array_values($deletes))->delete();

            if (count($can) !== $reservation_ids->count()) {
                return -1;
            }

            return $result;
        }

        return -2;
    }

    /**
     * 医生拒绝患者池中的患者
     * @param \App\User $doctor
     * @param           $pool_ids
     * @return bool|\Illuminate\Database\Eloquent\Collection|static
     */
    public function reject(User $doctor, $pool_ids)
    {
        $reject = new PoolReject();

        $pools = PoolModel::whereIn('id', $pool_ids)
                          ->select(['reservation_id', 'id'])
                          ->get();
        //  查找已拒绝过的,
        $hasBeenReject = $reject->select('reservation_id')->where('doctor_id', $doctor->id)
                                ->whereIn('reservation_id', $pools)->get()->pluck('reservation_id');

        if ($hasBeenReject->count()) {
            $pools = $pools->filter(function ($reservation) use ($hasBeenReject) {
                return false === $hasBeenReject->search($reservation->reservation_id);
            });
        }

        $insert = $pools->map(function ($reservation) use ($doctor) {
            return ['doctor_id' => $doctor->id, 'reservation_id' => $reservation->reservation_id];
        });

        if ($insert->count()) {
            \DB::table($reject->getTable())->insert($insert->toArray());

            return $pools;
        }

        return false;
    }

    protected function isHospitalAdmin()
    {
        return \Auth::user()->isA('nurse');
    }

    protected function poolFromReservation(Reservation $reservation, $create_time)
    {
        $pool = $reservation->toArray();

        $pool['created_at'] = $pool['updated_at'] = $create_time;

        return $pool;
    }

    protected function getReceptionMethod($reception = null)
    {
        if ($reception) {
            return [1 => 'hasNotReception', 2 => 'hasReception'][$reception];
        }

        return 'isReception';
    }
}